use x86::time as xtime;
use libuv::misc;
use std::thread;
use std::time::{Duration,Instant};
use chrono::prelude::*;

use super::umutex::{Umutex, ScopedLock};

#[derive(Debug,Default,Clone,Copy)]
pub struct UTime(pub i64);
#[derive(Debug,Default,Clone,Copy)]
pub struct UDuration(pub i64);
impl UTime {
    pub fn diff(&self, other: &UTime) -> UDuration {
        UDuration(self.0 - other.0)
    }
}

pub enum ClockMode {
    CpuClock,
    HardwareClcok,
    SysClock,
}

pub trait Clocker {
    fn now(&mut self) -> UTime;
}

#[derive(Debug,Default,Clone,Copy)]
pub struct SysTime(pub i64);
impl SysTime {
    pub fn now() -> SysTime {
        let local: DateTime<Local> = Local::now();
        let n = local.timestamp_nanos()
            - Local.ymd(2021, 1, 1)
                .and_hms_micro(0, 0, 0, 0)
                .timestamp_nanos();
        // let n = misc::hrtime() as i64;
        // let n = Instant::now() as i64;
        SysTime(n)
    }
    pub fn diff(&self, other: &SysTime) -> UDuration {
        UDuration(self.0 -other.0)
    }
}

pub trait SysConvertor {
    fn to_sys(&self,i:&UTime) -> SysTime;
    fn from_sys(&self,i:&SysTime) -> UTime;
}
pub struct Native {}
impl SysConvertor for Native {
    fn to_sys(&self,i:&UTime) -> SysTime {
        SysTime(i.0)
    }
    fn from_sys(&self,i:&SysTime) -> UTime {
        UTime(i.0)
    }    
}

#[derive(Debug,Default,Clone,Copy)]
pub struct UClockData {
    pub rate_nano : f64,
    pub cpu_start : SysTime,
    pub self_start : UTime,
    pub quality : f64,
}
#[derive(Debug,Default,Clone,Copy)]
pub struct UClock<T> where T:Clocker+Default {
    pub data : UClockData,
    pub clock : T,
}

#[repr(C)]
pub struct UClockExchange {
    data : UClockData,
    clk_mutex : Umutex
}

impl<T:Clocker+Default> UClock<T> {
    pub fn new() -> UClock<T> {
        let mut clock = T::default();
        let self_start0 = clock.now().0;
        let cpu_start = SysTime::now();
        let self_start1 = clock.now().0;
        thread::sleep(Duration::from_millis(1000));
        let end = clock.now().0;
        let self_start =(self_start0+self_start1)/2;
        let diff = end - self_start;
        UClock { 
            data : UClockData {
                cpu_start: cpu_start, 
                self_start: UTime(self_start as i64), 
                rate_nano:(diff as f64)/1e9,
                quality:1.0f64,
            },
            clock: clock
        }
    }
    pub fn from_data(d : &mut UClockExchange) -> Self {
        let _l = ScopedLock::new(&mut d.clk_mutex);
        Self { 
            data: d.data,
            clock: T::default(),
        }
    }
    pub fn to_data(&self,d : &mut UClockExchange) {
        let _l = ScopedLock::new(&mut d.clk_mutex);
        d.data = self.data;
    } 
}

impl SysConvertor for UClockData {
    fn to_sys(&self,i:&UTime) -> SysTime {
        let diff = i.0 - self.self_start.0;
        let cpu = self.cpu_start.0 + ((diff as f64)/self.rate_nano+0.5) as i64;
        SysTime(cpu)
    }
    fn from_sys(&self,i:&SysTime) -> UTime {
        let diff = i.0 - self.cpu_start.0;
        let ut = self.self_start.0 + ((diff as f64)*self.rate_nano+0.5) as i64;
        UTime(ut)
    }
}

impl<T:Clocker+Default> Clocker for UClock<T> {
    fn now(&mut self) -> UTime {
        self.clock.now()
    }
}

#[derive(Debug,Default,Clone,Copy)]
pub struct CpuClock{}

// #[cfg(target_arch ="86")]
impl Clocker for CpuClock {
    fn now(&mut self) -> UTime {
        let n = unsafe {xtime::rdtsc() as i64};
        UTime(n)
    }    
}




